package com.study.service.Impl;

import com.alibaba.fastjson.JSON;
import com.study.common.TableId;
import com.study.constant.GoodsConstant;
import com.study.dao.EcommerceGoodsDao;
import com.study.entity.EcommerceGoods;
import com.study.goods.DeductGoodsInventory;
import com.study.goods.GoodsInfo;
import com.study.goods.SimpleGoodsInfo;
import com.study.service.IGoodsService;
import com.study.vo.PageSimpleGoodsInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class IGoodsServiceImpl implements IGoodsService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private EcommerceGoodsDao ecommerceGoodsDao;

    @Override
    public List<GoodsInfo> getGoodsInfoByTableId(TableId tableId) {

        List<Long> ids = tableId.getIds().stream()
                .map(TableId.Id::getId)
                .collect(Collectors.toList());

        List<EcommerceGoods> ecommerceGoods = IterableUtils.toList(
          ecommerceGoodsDao.findAllById(ids)
        );

        return ecommerceGoods.stream()
                .map(EcommerceGoods::toGoodsInfo)
                .collect(Collectors.toList());
    }

    @Override
    public PageSimpleGoodsInfo getSimpleGoodsInfoByPage(int page) {

        if(page <= 1){
            page = 1;
        }

        //一页10条、按照id倒序排序
        Pageable pageable = PageRequest.of(
                page-1,10, Sort.by("id").descending());

        Page<EcommerceGoods> findPage  = ecommerceGoodsDao.findAll(pageable);

        boolean hasMore = findPage.getTotalPages() > page;

        List<SimpleGoodsInfo> list =  findPage.getContent().stream()
                .map(EcommerceGoods::toSimple).collect(Collectors.toList());
        return new PageSimpleGoodsInfo(list, hasMore);
    }

    @Override
    public List<SimpleGoodsInfo> getSimpleGoodsInfoByTableId(TableId tableId) {

        List<Object> goodIds = tableId.getIds().stream()
                .map(i -> i.getId().toString()).collect(Collectors.toList());

        //FIXME 如果cache 中查不到 goodsId对应的数据 返回的是 [null,null]
        List<Object> cacheSimpleGoodsInfos = redisTemplate.opsForHash()
                .multiGet(GoodsConstant.ECOMMERCE_GOODS_DICT_KEY,goodIds)
                .stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());


        //如果从redis 查出商品信息、分两种情况去操作
        if(CollectionUtils.isNotEmpty(cacheSimpleGoodsInfos)){
            //1.
            if(cacheSimpleGoodsInfos.size() == goodIds.size()){
                return parseCacheGoodsInfo(cacheSimpleGoodsInfos);
            }else {
                //2. 一是从数据表中获取 right对象、一是从redis中获取 left对象
                List<SimpleGoodsInfo> left =  parseCacheGoodsInfo(cacheSimpleGoodsInfos);
                //取差集:  传递的参数 - 缓存的数据 = 缓存没有的
                Collection<Long> substractIds = CollectionUtils.subtract(
                        goodIds.stream()
                        .map(g -> Long.valueOf(g.toString())).collect(Collectors.toList()),
                        left.stream()
                                .map(SimpleGoodsInfo::getId).collect(Collectors.toList())
                );
                //使用缓存没有的substractIds 查询数据库并且缓存
                List<SimpleGoodsInfo> right = goodsFromDBToRedis(
                        new TableId(substractIds.stream().map(TableId.Id::new)
                        .collect(Collectors.toList()))
                );
                return new ArrayList<>(CollectionUtils.union(left,right));
            }
        }else {
            return goodsFromDBToRedis(tableId);
        }
    }

    /**
     * 将缓存中的数据反序列化成 java pojo
     */
    private List<SimpleGoodsInfo> parseCacheGoodsInfo(List<Object> cacheSimpleGoodsInfo){
        return cacheSimpleGoodsInfo.stream()
                .map(s -> JSON.parseObject(s.toString(),SimpleGoodsInfo.class))
                .collect(Collectors.toList());
    }

    //从数据表中查询数据、缓存到redis中
    private List<SimpleGoodsInfo> goodsFromDBToRedis(TableId tableId){

        List<Long> ids = tableId.getIds().stream()
                .map(TableId.Id::getId).collect(Collectors.toList());

        List<EcommerceGoods> ecommerceGoods = IterableUtils.toList(
                ecommerceGoodsDao.findAllById(ids)
        );

        List<SimpleGoodsInfo> result = ecommerceGoods.stream()
                .map(EcommerceGoods::toSimple)
                .collect(Collectors.toList());

        Map<String,String> id2Json = new HashMap<>(result.size());
        result.forEach(g -> id2Json.put(
                g.getId().toString(),JSON.toJSONString(g)));

        //保存到redis中
        redisTemplate.opsForHash().putAll(GoodsConstant.ECOMMERCE_GOODS_DICT_KEY,id2Json);

        return result;
    }

    /**
     * 扣减商品库存信息
     * @param deductGoodsInventories
     * @return
     */
    @Override
    public Boolean deductGoodsInventory(List<DeductGoodsInventory> deductGoodsInventories) {

        //检验下参数是否合法
        deductGoodsInventories.forEach(d -> {
            if(d.getCount() <= 0){
                throw new RuntimeException("购买商品数量需要大于0!");
            }
        });

        List<EcommerceGoods> ecommerceGoods = IterableUtils.toList(
                ecommerceGoodsDao.findAllById( deductGoodsInventories.stream()
                        .map(DeductGoodsInventory::getGoodsId)
                        .collect(Collectors.toList()))
        );

        if(CollectionUtils.isEmpty(ecommerceGoods)){
            throw new RuntimeException("没有找到任何请求的商品");
        }

        if(ecommerceGoods.size() != deductGoodsInventories.size()){
            throw new RuntimeException("请求无效");
        }

        //goodsId -> deductGoodsInventories
        //list(deductGoodsInventories)转map(goodsToInventor)
        Map<Long,DeductGoodsInventory> goodsToInventor =
                deductGoodsInventories.stream()
                .collect(Collectors.toMap(DeductGoodsInventory::getGoodsId,
                        Function.identity()));

        //扣库存
        ecommerceGoods.forEach(g -> {
            Integer currentInventory = g.getInventory();
            Integer deductInventory =  goodsToInventor.get(g.getId()).getCount();
            if(currentInventory < deductInventory){
                throw new RuntimeException("商品库存不足: " + g.getId());
            }

            g.setInventory(currentInventory - deductInventory);

        });

        //保存入库
        ecommerceGoodsDao.saveAll(ecommerceGoods);
        return true;
    }
}
